package com.hjy.backend.versionManager;

import com.google.common.primitives.Bytes;
import com.hjy.backend.commons.SubArray;
import com.hjy.backend.dataManager.dataItem.DataItem;
import com.hjy.backend.utils.Parser;

import java.util.Arrays;

/**
 * VM向上层抽象出entry(记录)
 * entry结构：
 * [XMIN] [XMAX] [data]:创建该条记录（版本）的事务编号, 删除该条记录（版本）的事务编号,记录持有的数据
 */
public class Entry {
    private static final int OF_XMIN = 0;
    private static final int OF_XMAX = OF_XMIN + 8;
    private static final int OF_DATA = OF_XMAX + 8;

    private long uid; // DataItem 和 Entry 的唯一标识
    private DataItem dataItem;
    private VersionManager vm;

    public static Entry newEntry(VersionManager vm, DataItem dataItem, long uid) {
        Entry entry = new Entry();
        entry.uid = uid;
        entry.dataItem = dataItem;
        entry.vm = vm;
        return entry;
    }

    /**
     * 加载一个Entry(实际上调用的是DataManager的read方法)
     *
     * @param vm
     * @param uid
     * @return
     * @throws Exception
     */
    public static Entry loadEntry(VersionManager vm, long uid) throws Exception {
        DataItem di = ((VersionManagerImpl) vm).dm.read(uid);
        return newEntry(vm, di, uid);
    }

    /**
     * 包装一个entry格式
     *
     * @param xid
     * @param data
     * @return
     */
    public static byte[] wrapEntryRaw(long xid, byte[] data) {
        byte[] xmin = Parser.long2Byte(xid);
        byte[] xmax = new byte[8];
        return Bytes.concat(xmin, xmax, data);
    }

    public void release() {
        ((VersionManagerImpl) vm).releaseEntry(this);
    }

    /**
     * 释放对应的 dataItem
     */
    public void remove() {
        dataItem.release();
    }

    /**
     * 读取这个记录的数据(从DataItem中)
     *
     * @return
     */
    public byte[] data() {
        dataItem.rLock();
        try {
            // TODO 这里 dataItem 已经是纯数据了, 还要进行处理, 不太明白, 或者说这里本来存储的就是这样的形式(带事务号)
            SubArray sa = dataItem.data();
            byte[] data = new byte[sa.end - sa.start - OF_DATA];
            System.arraycopy(sa.raw, sa.start + OF_DATA, data, 0, data.length);
            return data;
        } finally {
            dataItem.rUnLock();
        }
    }

    /**
     * 获取这个记录创建时的事务号
     *
     * @return
     */
    public long getXmin() {
        dataItem.rLock();
        try {
            SubArray sa = dataItem.data();
            return Parser.parseLong(Arrays.copyOfRange(sa.raw, sa.start + OF_XMIN, sa.start + OF_XMAX));
        } finally {
            dataItem.rUnLock();
        }
    }

    /**
     * 获取这个记录修改或删除的事务号
     *
     * @return
     */
    public long getXmax() {
        dataItem.rLock();
        try {
            SubArray sa = dataItem.data();
            return Parser.parseLong(Arrays.copyOfRange(sa.raw, sa.start + OF_XMAX, sa.start + OF_DATA));
        } finally {
            dataItem.rUnLock();
        }
    }

    /**
     * 设置这个记录修改或删除的事务号
     *
     * @return
     */
    public void setXmax(long xid) {
        // 这个地方, 记录一下修改日志
        dataItem.before();
        try {
            SubArray sa = dataItem.data();
            System.arraycopy(Parser.long2Byte(xid), 0, sa.raw, sa.start + OF_XMAX, 8);
        } finally {
            dataItem.after(xid);
        }
    }

    public long getUid() {
        return uid;
    }
}
